/******************************************************************************
Main Javascript module for BBKB
Acts as basic controller + model.
******************************************************************************/
BBKB = function() {
	/** Private **/
	var teams = [];
	var teams_lookup = {};
	var players = [];
	
	/**
		Read base JSON record into flattened map and store it in the
		team member variable.
	*/
	var parseLeagueRecords = function(league_record) {
		$(league_record.conferences).each(function(index, conf) {
			$(conf.teams).each(function(index,team) {
				team.league = league_record.league;
				team.conference = conf.conference;
				team.players = ALL_PLAYERS[team.shortcode];
				teams.push(team);
				
				/* Aggregate all of the players */
				$(ALL_PLAYERS[team.shortcode].Players).each(function(index, player) {
					players.push(player);
				});
			});
		});
	};
	
	/** 
	  Utility function to make player names "First Last" instead of "Last, First"
	**/
	var switchPlayerNames = function() {
		$(players).each(function(idx,player) {
			var names = player.name.split(',');
			player.name = names[1].trim() + ' ' + names[0].trim();
		});
	}
	
	/** 
		Apply query 
		dataset - the collection of data to query
		attr - attribute to query
		value - value to query with
		op - the query operation to perform
	*/
	var apply_query = function(dataset, attr, value, op) {
		var results = [];
		$.each(dataset, function(idx,item) {
			var found = false;
			var comparators = null;
			/** expand arrays in attributes */
			if (item[attr].constructor == Array) {
				comparators = item[attr];
			} else {
				comparators = [item[attr]];
			}
			$.each(comparators, function(idx, cmp) {
				var val = convertArgs(cmp, value);
				if (op.op(val[0], val[1])) { found = true; }
			});
			if (found) {
				results.push(item);
			}
		});
		return results;
	}
	
	/** Handle simple query */
	var perform_simple_query = function() {
		var attr = $('#simpleQueryAttribute option:selected').val();
		var op = find_by_key(SimpleOperations, $('#simpleQueryOperation option:selected').val(),'key');
		var value = $('#simpleQueryValue').val();
		UI.display_team_table(apply_query(teams,attr,value,op));
	};
	
	/** Handle aggregate query */
	var perform_frequency_query = function() {
		var attr = $('#aggregateQueryAttribute option:selected').val();
		var counts = {};

		$.each(teams, function(team_idx, team) {
			var vals = null;
			/** expand arrays in attributes */
			if (typeof team[attr] !== 'string' && team[attr].constructor == Array) {
				vals = team[attr];
			} else {
				vals = [team[attr]];
			}
			$.each(vals, function(idx, value) {
				if (counts.hasOwnProperty(value)) {
					counts[value] = counts[value] + 1;
				} else {
					counts[value] = 1;
				}
			});
		});
		UI.display_frequency_table(sort_dict(counts,-1));
		
	};
	
	var perform_nlp_query = function() {
		var query = NLP.construct_query();
		if (query) {
			var isPlayerQuery = query.subject == 'players';
			var dataset = isPlayerQuery ? players : teams;
			var op = find_by_key(SimpleOperations, query.operation, 'value');
			var results = apply_query(dataset, query.attr, query.value, op);
			UI.display_nlp_results(query, results);			
			if (isPlayerQuery) {
				var pTeams = []
				$(results).each(function(idx,player) {
					var team = teams_lookup[player.team];
					if ($.inArray(team, pTeams) < 0) {
						pTeams.push(team);
					}
				});
				// swap new team results in
				results = pTeams;
			}
			UI.display_team_table(results);
		}
	};
		
	/** Utility function to locate items in maps with key/value names entries */
	var find_by_key = function(collection, key, keyname) {
		var found = null;
		var keyname = keyname || key;
		$.each(collection, function(idx, value) {
			if (value[keyname] === key) {
				found = value;
				return false;
			}
		});
		if (found) {
			return found;
		} else {
			throw "Value [" + key + "] was not found in collection with key name [" + keyname +"]";
		} 
	};
	
	/** utility method to sort associative array
		@param desc Pass in -1 for descending order
		source: http://stackoverflow.com/questions/5199901/how-to-sort-an-associative-array-by-its-values-in-javascript
	*/
	var sort_dict = function(data, desc) {
		var tuples = [];
		var dir = desc || 1;
		$.each(data, function(key, value) {	tuples.push([key, value]); });
		tuples.sort(function(a,b) {
			x = a[1];
			y = b[1];
			if (a[1] < b[1]) return dir*-1;
			if (a[1] > b[1]) return dir*1;
			if (a[0] < b[0]) return -1;
			if (a[0] > b[0]) return 1;
			return 0;
		});
		return tuples;
	};
		
	/** Public **/
	return {
		/** 
			Constructor - Reads and stores knowledgebase from our underlying datasets.
		*/
		init : function() {
			
			/** Parse team datasets **/
			parseLeagueRecords(NATIONAL_LEAGUE);
			parseLeagueRecords(AMERICAN_LEAGUE);
			$(teams).each(function(idx,team) {
				teams_lookup[team.shortcode] = team;
			});
			
			/** Cleanup player data **/
			switchPlayerNames();

			/** Handle UI hookups */
			$('#doSimpleQuery').click(function(e) { e.preventDefault(); perform_simple_query(); });
			$('#resetSimpleQuery').click(function() { UI.display_team_table(teams); });
			
			$('#doAggregateQuery').click(function(e) { e.preventDefault(); perform_frequency_query(); });
			
			$('#doNLPQuery').click(function(e) { e.preventDefault(); perform_nlp_query(); $( "#nlpResults" ).show();});
			$('#resetNLP').click(function(e) { $( "#nlpResults" ).hide();});
			
			$( "#toggleLog" ).click(function(e) { e.preventDefault();  UI.toggleLogVisibility(); });
			$( "#toggleResults" ).click(function(e) { e.preventDefault();  UI.toggleResultsVisibility(); });
		},
		
		/** Show all teams **/
		show_all_teams : function() {
			UI.display_team_table(teams);
		},
		
		/** log **/
		log : function( message ) {
			UI.log(message);
		}
	}
}();

function convertArgs(a,b) {
	if (isNaN(a) || isNaN(b)) {
		return [a.toLowerCase(),b.toLowerCase()];
	} else {
		return [parseInt(a), parseInt(b)];
	}
}

